//
//
//正数的源码反码补码都是一样的     负数的反码就是除了符号位所有位按位取反       负数的补码也就是在反码的基础上加1
//
//
//
//分类
//算数操作符   移位操作符   位操作符   赋值操作符   单目操作符   关系操作符   逻辑操作符  条件操作符   逗号表达式   下标引用，函数调用和结构成员
//
//1.算数操作符
//除了%操作符外，其他几个操作符可以作用于整数和浮点数.也就是说%只能操作的是整数              -----%操作符只能操作整数
//
//对于/操作符如果操作数都为整数，执行整数除法。而只要有浮点数执行的就是浮点数除法。
//
//double双精度变量的是默认打印后面六位小数
//
//
//
//
//
//
//
//
//2.移位操作符通    （不能对浮点数进行操作）
// 计算机中存储的是数字二进制的补码   源码是直接表示这个数字的大小的   正数的源码反码补码是相同的                 -----移位操作操作的是数字二进制的补码，无论证整数还是负数
//
// 移位的过程中移动的是负数的补码，正数的源码补码反码都一样
//
//整形有符号数字在内存中是以源码反码补码的方式进行存储。
// 浮点数的存储方式并不是源码反码补码的形式进行的存储
// 无符号整形的变量源码补码反码是一样的，并且最前面不是符号位，而是和其他位一样表示变量的大小的
// 
// 二进制最前面的0表示正数  1表示的是负数
//
//（1）右移操作符  >>
//右移操作符:移动的是二进制补码   例如a>>2 这就是将a的整个2进制位向右移动了两位    即0001000变成了0000010       -----右移一位相当于对原数除以2,无论是正数还是负数
//请注意：移位的时候右边舍弃的是0，相当于对原数除以2，但是如果舍弃的是1，原来的数字就会发生改变
//
//右移的方法分两种，一种是算数右移（大部分编译器所采用的），一种是逻辑右移
//算数右移：右边丢弃，左边补原来的符号位。原来是正数还是正数，原来是负数还是负数                 -----右边舍弃的时候请注意有没有舍弃有效数字位
//逻辑右移：右边直接丢弃，左边补零          -----逻辑右移移位后数字可能会发生改变
//
//左移的规则就是左边丢弃右边补零      000101左移一位就是 001010   也就是乘以2              -----左移一位相当于原数字乘以2，无论正负数
//请注意：左移的时候也得注意是否移动了有效数字位。有可能将补码中的1舍弃完，然后0到符号位改变数字的1正负             -----负数左移的时候可能会变为正数并且乘以2
//
//对于移位操作符不要移动负数位，这个是标准未定义的 也就是int a=10   a>>-2        -----移动符号位只能是正数，不能移动-1 -2之类的
//
//将参数额传给形参，形参进行位位操作运算并不会对形参进行改变
//
//
//
//
//
//
//
//3.位操作符           （不能对浮点数进行操作） 操作的同样是数字的补码
//&按位与     |按位或     ^按位异或
//
//0异或任何数都不变，1异或任何数都取非。但是这个执行效率并没有第三者变量高
//
//n=n&(n-1),原来的源码二进制位中有多少1，这个n在变为0之前就会执行多少次   也就是该代码码会让余下最右边的1变为0，直到0000
//
//
//4.单目操作符
//`>>>这个是波浪号，也是对该数字二进制位所有的位进行取反，此时得到的是补码。屏幕上显示的也是根据这个`运算后补码所获得的源码。
//就比如0.  其源码00000000，`>>>按位取反后得到的二进制补码位11111111>>>根据这个补码所得反码为>>>11111110>>>最后屏幕上显示的是10000001  也就是-1
//
//5.* 这个非常重要解引用操作符，后续关于指针会详细解释
//
//
//
//6.(类型)    也就是强制类型转换
//注意强制类型转换的形式>>>float a=3.15   a=(int)a;
//
//7.sizeof和数组
//sizeof 对于变量允许不使用括号>>>int arr[];   sizeof arr;但是对于类型必须要加符号>>>sizeof (int);
//
//对于一维数组来说，数组作为函数参数传递，实际上传递了一个指向数组的指针，当数组名作为函数参数时，函数体内的数组自动退化为指针，调用函数时相当于传址
//而不是传值。传递二维参数时一定要注意著名列数，形式参数也要注明列数,二维数组的行可以不定义，但是列一定要定义
//#include<stdio.h>
//void test1(int arr[])
//{
//	printf("%d\n", sizeof(arr));//8
//}
//
//void test2(char arr[])
//{
//	printf("%d", sizeof(arr));//8
//}
//int main()
//{
//	int arr[10] = { 0 };
//	char ch[10] = { 0 };
//	printf("%d\n", sizeof(arr));//40>>>在上面有定义数组的时候，这个数组名就代表了整个数组所占的空间
//	printf("%d\n", sizeof(ch));//10>>>和上面一样的道理
//	test1(arr);//当做传形参时仅仅是第一个元素的首地址，地址需要指针变量接收。不论什么类型的指针都是（32）4个字节/(64)8个字节
//	test2(ch);
//	return 0;
//}
//
//
//
//
//
//
//
//
//
//8.逻辑与&&和逻辑或||
//#include<stdio.h>
//int main()
//{
//	int i = 0, a = 0, b = 2, c = 2, d = 4;
//	i = a++ && ++b && d++;//&&左边如果为假，&&右边的不进行计算和判断，则后面的直接跳过不判断>>>++b d++则不进行运算。当左边为真时则会一直向右判断
//
//	//当为||>>>也就是逻辑或的，只要||左边为真，则不向右继续判断
//	return 0;
//}
//
//
//
//
//
//
//
//
//
//9.条件操作符
//判断表达式？结果1：结果2；         >>>表达式从左向右，依次运算。结果为真则为结果1，否则为结果2       这个表达式还可以进行赋值>>>max=a>b?a:b;
//这个就是三目运算符，也就是一共操作了三个数或者条件以及条件或者变量的混合
//
//
//
//
//
//
//
//
//
//10.逗号表达式
//表达式1，表达式2，表达式3.......，表达式n>>>表达式的最后一个结果会赋值给等号左边。其余的表达式虽然会计算，但不会向前面传值，但是其中计算的数值会变化
//int a=2,int b=5   int c=(a>b,a=b+10,a,b=a+1)>>>运算后a=15,b=16,然后16赋值给c    a+10（不是a=a+10）放在中间则不会进行计算。放在最后面则会进行
//计算并且会向前传值
//if(,,,)放在条件表达式的时候最后一个真才会判断真，最后一个假则判断假
//逗号表达式里面的++和--不在最后面，同样也会改变年变量的值
//
//
//
//
//
//
//
//
//
//11.下标引用、函数调用和结构成员
//[]>>>下标引用操作符      操作数：一个数组名一个索引值>>>也就是int arr[];rintf("%d",arr[3]),这就算下标引用了
//
//函数调用操作符（），也就是调用函数的时候声明，以及传参。
//
//结构成员
//和java的对象很相似
//#include<stdio.h>
//void main()
//{
//	struct Student//创建了一个结构体类型，结构体也能放在主函数的外面，使用的时候同样可以像其创建的其他方法一样进行调用
//	{
//		char name[20];//这就是结构体的属性
//		int age;
//		char id[20];
//	};//注意！注意！注意！结构体的大括号后面有一个分号结束
//
//	struct Student s1 = { "张三",20,"191112345678" };           -----调用结构体变量并且初始化,也就只有这个时候才能将所有的变量全部在同一个大括号里面进行赋值
//	struct Student *p = &s1;//创建了一个结构体的指针存放学生s1的地址      创建结构体指针变量的时候一样要带上结构体类型的名字 struct Student!
//	printf("%s", (*p).name);//单独一个p打印出来的是地址，也就是那一串数字，带上*就是解引用操作符，单独输出某一变量的时候则需要进行（*p）.name
//	printf("%s", p->name);//这种写法和上面那个name完全是一样的   结构体指针名字->成员名字
//	printf("%s", s1.name);//这个.就是调用函数的成员变量的
//}
//
//
//
//
//
//
//
//
//
//12.表达式进行求值                  -----字符类型和短整型才会进行整型提升
//表达式求值的顺序一部分是由操作符的优先级和结核性决定，同样有些表达式的操作数在求值的过程中可能需要转换为其他类型
//
//隐式类型转换>>>表达式中各种长度小于int长度的整型值都必须要转换为int或者unsignedint才能送入cpu进行运算
// 少以缺省整型类型的精度来进行的。为了获得这个精度，表达式中的字符和短整型操作数在使用之前被转换为普通整形，这种转换被称为整形提升
//char a,b,c;a=b+c>>>b和c会先提升为普通整形，然后再执行加法运算，加法运算完成之后，结果将被截断，也就是4个字节砍得就剩一个字节，符号位也可能会改变
//>>>00000000000000000000000011111111这个数为两者提升后相加的二级制，也就是正数130，然后会被截断为一个字节11111111也就是变为负数-126
//
//
//
//
//整型提升
//
//只要有运算符的出现，并且运算的变量不够4个字节，就需要整型提升
//
//char a,char b; printf("%d",a+b)这种整型提升是在运算的过程中进行整型提升的，不会发生截断      -----这种的是在整型提升的过程中进行输出的，不会发生截断
//
//char c=a+b;printf("%d,c);这种情况再运算的过程中也会整型提升，但是会发生截断，将c截成8个位数大小，输出c的时候会再次进行整型提升
//注意在整型提升的过程中，如果定义的变量是一个无符号整型，那么提升时补位均为0，如果不是无符号位整型变量，那么提升的过程补位的数字和最高位保持一致
//注意：以%d格式输出字符类型的变量，这个变量仅在输出的这个过程会进行整型提升，但是在输出完之后，这个变量的大小依然是1个字节
//
//
//算数转换再看看
//操作符的优先级结合性得看看   会控制求值顺序例如&&左边为假则不会在向右判断
//
//注意一个同一个变量不要在一个表达式中进行++ --之类的运算。  
//
//优先级：+ 大于 +=   =大于，      
//
//int 类型和unsigned int 类型进行比较的时候，int类型会提升至unsigned int类型，也就是说负数会转换成一个很大的数进行比较
//#include <stdio.h>
//int i;
//int main()
//{
//    i--;
//    if (i > sizeof(i))
//    {
//        printf(">\n");    //实际上会输出这个语句
//    }
//    else
//    {
//        printf("<\n");
//    }
//    return 0;
//}
//







//补充：：波浪号按位取反"~"              -----这个操作符同样能改变补码的符号位
//
//     
//  只要是整数，内存中储存的都是二进制的补码    正数--源码、补码、反码相同       负数--源码反码补码有自己的机制
// 
//#include<stdio.h>
//int main()
//{
//	int a = 0;                               //0000    这个是源码
//	int b = ~a;//"~"按位（二进制位）取反 ,b是有符号的整形    //b存储的二进制位是1111，存的即补码
//	负数在存储的时候，存储的是二进制的补码，二进制最前面的一位是符号位，代表正负
//	printf("%d", b);//打印是-1    因为整数的源反补是一样的，这个按位取反操作的还是补码，此时取反以后是一个负数的补码。根据源反补的规则，得出负数的源码为 10000.....1
//	return 0;
//}








//补充：：移位符               ----移动的是数字的二进制的补码
//#include<stdio.h>
//int main()
//{
//	short a = 1;
//	short b,c;
//	b = a << 2;//"<<"--左移位符  ">>"--右移位符   移动的是二进制位a=1即0000000000000001，左移动二位--即00000000000000100，在二进制中表示4.  如果是右移，移几个右边去掉几个，左边加上0   
//	printf("%d\n",b);
//                     //
// 
//	c = a >> 2;
//	printf("%d\n", c);
//	printf("%d\n", sizeof(c));
//	return 0;
//}
//










//补充::位操作符  位操作符操作的都是补码，并且操作符号位
// 可以按着&&和||理解，第一个是都真才真（也就是且），第二个是有真即真（也就是或）
//#include<stdio.h>
//int main()
//{
//	位操作符（2进制）     -----再次强调一下这些位操作符操作的都是数字的二进制补码


//	"&" 按位与----补码的进制位上下对齐 ,只有都是1的时候才取“1”   0和0、0和1，都取0
//	"|"按位或 ，上下对齐，有真取真，无真取0
// 
// 
//	"^"按位异或----对应的二进制位相同则为0，相异则为1                    -----其中异或满足交换律     
//异或的特性：
//（1）两个相同的数字异或为0
//（2）0与任何数字异或都是本身
//（3）异或满足交换和结合律
//（4）


//	int a = 3;//0011                                                                                                             //x^x=0   x^0=x   x^y^z=x^z^y---异或满足交换律
//	int b = 5;//0101                                                                                                             //
//	int c = a & b;//0001                                                                                                          
//	int d = a ^ b;   //0110  记得在这里不是次方的意思，这是异或，相异取1，相同取0
//	printf("%d\n", c);
//	printf("%d\n", d);
//	a += 10;//即a=a+10,第一个字符就是需要操作的，后面的都是进行运算的
//	return 0;
//
//}
//补充：这些位操作符也能操作符号位

//补充：两个相同的数异或为0，任何数异或0都是本身      并且异或还有个类似交换律的特性（一堆数字任意交换位置全部异或，最后的值不变）
//也就是a^b^c^g^a^b^c=g;
// 
// 这个就是不用第三方变量交换两数的值
//#include<stdio.h>
//int main(void)
//{
//	int a = 1;
//	int b = 2;
//	a = a ^ b;//此时a是两者的异或
//	b = a ^ b;//两者的异或再异或b就是a
//	a = a ^ b;//a此时还是两者的异或，b已经是a最开始的值，两者异或就是b
//	printf("a:%d,b:%d", a, b);
//}



